package com.ido.wechat.client;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ido.wechat.configuration.WechatConfiguration;
import com.ido.wechat.constants.WxConstants;
import com.ido.wechat.params.LoginParam;
import com.ido.wechat.bean.SubMessage;
import com.ido.wechat.params.VerifyParam;
import com.ido.wechat.vo.WxLogin;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 微信小程序/公众号服务
 * Create by zoub
 * Date 2022/11/10 下午8:42
 */
@Slf4j
@Component
public class WechatClient {

    @Autowired
    private WechatConfiguration wechatConfiguration;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 开发者验证
     * @param verifyParam
     * @param request
     * @param response
     * @return
     */
    public String verify(VerifyParam verifyParam, HttpServletRequest request, HttpServletResponse response) {
        log.info("【Wechat-开发者验证】：verifyParam => {}", JSON.toJSONString(verifyParam));

        // 将请求、响应的编码均设置为UTF-8（防止中文乱码）
        try {
            request.setCharacterEncoding("UTF-8");
            response.setCharacterEncoding("UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }

        // 字段排序后sha1加密
        String[] params = {wechatConfiguration.getToken(), String.valueOf(verifyParam.getTimestamp()), verifyParam.getNonce()};
        Arrays.sort(params);
        log.info("[1]{} , [2]{}, [3]{}", params[0], params[1], params[2]);
        String result = DigestUtils.sha1Hex(params[0] + params[1] + params[2]);
        log.info("加密后： {}", result);

        // 验证成功，需向微信服务器给出响应
        return result.equals(verifyParam.getSignature()) ? verifyParam.getEchostr() : "";
    }

    /**
     * 获取认证token
     */
    public String getToken() {
        Object accessToken = redisTemplate.opsForValue().get(WxConstants.wxAccessToken);
        if (Objects.nonNull(accessToken)) {
            return String.valueOf(accessToken);
        }

        Map<String, Object> map = new HashMap<>();
        map.put("appid", wechatConfiguration.getAppid());
        map.put("secret", wechatConfiguration.getSecret());
        map.put("grant_type", wechatConfiguration.getGrantType());
        log.info("【Wechat-获取认证Token】, param：{}", map);

        String result = HttpUtil.get(wechatConfiguration.getTokenUrl(), map);
        JSONObject body = JSONObject.parseObject(result);
        log.info("body：{}", body);

        String access_token = body.getString("access_token");
        String expires_in = body.getString("expires_in");
        redisTemplate.opsForValue().set(WxConstants.wxAccessToken, access_token);
        redisTemplate.expire(WxConstants.wxAccessToken, Long.parseLong(expires_in), TimeUnit.SECONDS);
        return access_token;
    }

    /**
     * 小程序登录
     *
     * @param param
     * @return
     */
    public WxLogin login(LoginParam param) {
        Map<String, Object> map = new HashMap<>();
        map.put("appid", wechatConfiguration.getAppid());
        map.put("secret", wechatConfiguration.getSecret());
        map.put("grant_type", wechatConfiguration.getGrantType());
        map.put("js_code", param.getCode());
        log.info("【Wechat-登录】, param：{}", map);

        String body = HttpUtil.get(wechatConfiguration.getLoginUrl(), map);
        log.info("body：{}", body);

        // 微信用户的openId存入缓存
        return JSONObject.parseObject(body, WxLogin.class);
    }


    /**
     * 获取手机号
     * @return
     */
    public String getPhoneNumber(String code) {
        Map<String, Object> map = new HashMap<>();
        map.put("code", code);
        log.info("【Wechat-获取手机号】, param：{}", map);
        String token = this.getToken();
        String url = wechatConfiguration.getPhoneNumberUrl();
        if (StringUtils.isNotBlank(url)){
            url =  url.replace(WxConstants.accessToken, token);
        }
        String result = HttpUtil.post(url, JSON.toJSONString(map));
        log.info("result：{}", result);
        return result;
    }

    /**
     * 发送订阅消息
     *
     * @param message
     * @return
     */
    public void sendSubMessage(SubMessage message) {
        log.info("【Wechat-发送订阅消息】, message：{}", JSON.toJSONString(message));
        String token = this.getToken();
        String url = wechatConfiguration.getSendSubMsgUrl();
        if (StringUtils.isNotBlank(url)){
            url =  url.replace(WxConstants.accessToken, token);
        }
        String body = HttpUtil.post(url, JSON.toJSONString(message));
        log.info("body：{}", body);
    }


}
